/**
 * @file bitmap.c
 * @author lcz (you@domain.com)
 * @brief
 * @version 0.1
 * @date 2022-10-26
 *
 * @copyright Copyright (c) 2022
 *
 */

#include "tools/bitmap.h"
#include "tools/kilb.h"
/**
 * @brief 获取所需要的字节数量
 */
int bitmap_byte_count(int bit_count)
{
    return ((bit_count + 8 - 1) / 8);
}
/**
 * @brief 位图初始化
 */
void bitmap_init(bitmap_t *bitmap, uint8_t *bits, int count, int init_bit_value)
{
    bitmap->bits = bits;
    bitmap->bit_count = count;
    int bytes = bitmap_byte_count(bitmap->bit_count);
    kernel_memset(bitmap->bits, (init_bit_value ? 0xff : 0), bytes);
}
/**
 * @brief 获取指定位的状态
 */
int bitmap_get_bit(bitmap_t *bitmap, int index)
{
    // 0 return 0,1 return +N
    // 注意，若对应的位为0，则相与后返回0，若对应位值不为1，结果不一定为1，为2的n次幂
    return bitmap->bits[index / 8] & (1 << (index % 8));
}

/**
 * @brief
 *
 * @param bitmap bitmap结构体
 * @param index 位图索引下标
 * @param count 连续设置的bit位数
 * @param bit   设置的值
 */
void bitmap_set_bit(bitmap_t *bitmap, int index, int count, int bit)
{

    for (int i = 0; (i < count) && (index < bitmap->bit_count); i++, index++)
    {
        if (bit)
        {
            // 设置位为1
            bitmap->bits[index / 8] |= (1 << (index % 8));
        }
        else
        {
            // 设置位为0
            bitmap->bits[index / 8] &= ~(1 << (index % 8));
        }
    }
}
/**
 * @brief 检查指定位是否置1
 */
int bitmap_is_set(bitmap_t *bitmap, int index)
{
    // 由于调用的是bitmap_get_bit，因此bitmap_get_bit返回值处理后再返回
    return bitmap_get_bit(bitmap, index) ? 1 : 0;
}

/**
 * @brief 查找连续比特位值位bit的首索引
 *
 * @param bitmap
 * @param bit
 * @param count
 * @return int
 */
int bitmap_alloc_nbits(bitmap_t *bitmap, int bit, int count)
{
    int search_index = 0;
    int ok_index = -1;
    // 遍历所有比特位
    while (search_index < bitmap->bit_count)
    {
        //
        // 稍微修改一下 bitmap_get_bit 返回值改为0与1
        //
        if ((bitmap_get_bit(bitmap, search_index) ? 1 : 0) != bit)
        {
            search_index++;
            continue;
        }
        ok_index = search_index;
        int i;
        for (i = 1; (i < count) && (search_index < bitmap->bit_count); i++)
        {
            if (bitmap_get_bit(bitmap, search_index++) != bit)
            {
                ok_index = -1;
                break;
            }
        }
        // 如诺i大于等于count，说明找到对应的数据块
        if (i >= count)
        {
            // 找连续的值为bit的位，并对位值取反
            //  ~bit 这个需要验证一下
            bitmap_set_bit(bitmap, ok_index, count, ~bit);
            return ok_index;
        }
    }
    return ok_index;
}